#include "cppTutorGlobals.h"
#include "cppTutorMultiThreading.h"

#include <iostream>
#include <string.h>
#include <stdio.h>

// log framework
#include "cppTutorLog.h"
extern CcppTutorLog Log;

using namespace std;

int CcppTutorMultiThreading :: nSharedData = 0;

CcppTutorMultiThreading :: CcppTutorMultiThreading () : thread_id (0), a(1), b(2), m_nReturnStatus (0)
{
    Log << "ENTER : CcppTutorMultiThreading :: CcppTutorMultiThreading ()" << endl;
    Log << "EXIT  : CcppTutorMultiThreading :: CcppTutorMultiThreading ()" << endl;
}

CcppTutorMultiThreading :: ~CcppTutorMultiThreading ()
{
    Log << "ENTER : CcppTutorMultiThreading :: ~CcppTutorMultiThreading ()" << endl;
    Log << "EXIT  : CcppTutorMultiThreading :: ~CcppTutorMultiThreading ()" << endl;
}

int CcppTutorMultiThreading  :: m_CreateThread ()
{
    Log << "ENTER : CcppTutorMultiThreading :: m_CreateThread ()" << endl;
    #ifdef MULTI_THREAD
        for( i=0; i < NUM_THREADS; i++ )
        {
            cout << "main() : creating thread, " << i << endl;
            td[i].thread_id = i;
            td[i].message = "This is message";
            #ifdef WIN32
            // windows thread
            #else
            rc = pthread_create(&threads[i], NULL, PrintHello, (void *)&td[i]);
            #endif
            if (rc)
            {
                cout << "Error:unable to create thread," << rc << endl;
                exit(-1);
            }
        }
    #else
        /* create a new thread that will execute 'do_loop()' */
        #ifdef WIN32
        // windows thread create
        #else
        thread_id = pthread_create(&p_thread, NULL, do_loop, (void*)&a);
        #endif
        if (thread_id)
        {
            cout << "Error:unable to create thread," << thread_id << endl;
            exit(-1);
        }        
        /* run 'do_loop()' in the main thread as well */
        do_loop((void*)&b);
    #endif //MULTI_THREAD
    Log << "EXIT  : CcppTutorMultiThreading :: m_CreateThread ()" << endl;
    #ifdef WIN32
    // windows thread
    #else    
    pthread_exit(NULL);
    #endif
    return m_nReturnStatus;
}

int CcppTutorMultiThreading :: m_JoiningDetachingThreads ()
{
   // Initialize and set thread joinable
    #ifdef WIN32
    // windows thread
    #else       
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    #endif
    
    for( i=0; i < NUM_THREADS; i++ )
    {
        cout << "main() : creating thread, " << i << endl;
        #ifdef WIN32
        // windows thread
        #else
        rc = pthread_create(&threads[i], NULL, wait, (void *)i );
        #endif
        if (rc)
        {
            cout << "Error:unable to create thread," << rc << endl;
            exit(-1);
        }
    }

    // free attribute and wait for the other threads
    #ifdef WIN32
    // windows thread
    #else        
    pthread_attr_destroy(&attr);
    #endif
    for( i=0; i < NUM_THREADS; i++ )
    {
        #ifdef WIN32
        // windows thread
        #else    
        rc = pthread_join(threads[i], &status);
        #endif
        if (rc)
        {
            cout << "Error:unable to join," << rc << endl;
            exit(-1);
        }
        cout << "Main: completed thread id :" << i ;
        cout << "  exiting with status :" << (long)status << endl;
    }

    cout << "Main: program exiting." << endl;
    #ifdef WIN32
    // windows thread
    #else        
    pthread_exit(NULL);
    #endif
	return 0;
}

#ifdef MUTEX_DEMO
int CcppTutorMultiThreading :: useMutex()
{
    Log << "ENTER : CcppTutorMultiThreading :: useMutex ()" << endl;
    
    mutexDemo ();
    
    Log << "EXIT  : CcppTutorMultiThreading :: useMutex ()" << endl;
    
    return 0;
}
#endif //MUTEX_DEMO
